package main

import (
	"fmt"
	"runtime"
	"time"
)

//go run -race main.go 命令可以检测出是否存在数据冲突

//goroutine 切换点：I/O select； channel ； 等待锁； 函数调用（有时）； runtime.Gosched() ; 其他可能的切换
func main() {

	//example1()
	example2()

}

func example1() {
	var a [10]int
	for i := 0; i < 10; i++ {
		//如果不将i作为参数传入，而使用闭包的方式在匿名函数中使用i变量，会出现数据冲突的情况。
		go func(ii int) {
			for {
				a[ii]++
				runtime.Gosched() //主动交出控制权，让其他协程工作  1.13以前的版本如果不主动交出控制权会死锁（此匿名函数一直在执行导致main被挂起）
			}
		}(i)
	}

	time.Sleep(time.Millisecond)
	fmt.Println(a)
}

func example2() {
	var a [10]int
	for i := 0; i < 1000; i++ {
		//如果不将i作为参数传入，而使用闭包的方式在匿名函数中使用i变量，会出现数据冲突的情况。
		go func(i int) {
			for {
				fmt.Printf("gorountine: %d\n", i) //不需要runtime.Gosched()来主动交出控制权，作因为print会发生io，操系统会进行切换。
			}
		}(i)
	}

	time.Sleep(time.Minute)
	fmt.Println(a)
}
